#pragma once

#include <AVUIDispatcher.h>

namespace AVUI {

class LayoutEventList : public Object
{
public:

#pragma region Internal ListItem

    class ListItem : public Object
    {
    public:
        ListItem() : Prev(NULL), InUse(false) { }
        TWeakPtr<Object> Target;
        bool InUse;
        TRefCountedPtr<ListItem> Next;
        ListItem* Prev;
    };

#pragma endregion Internal ListItem


#pragma region Internal Methods
    LayoutEventList() : m_count(NULL)
    {
        for (int i = 0; i < PocketCapacity; i++)
        {
            TRefCountedPtr<ListItem> pItem = object_allocate<ListItem>();
            pItem->Next = m_pPocket;
            m_pPocket = pItem;
        }
        m_pocketSize = PocketCapacity;
    }

    ListItem* Add(Object* pTarget)
    {
        TRefCountedPtr<ListItem> pItem = getNewListItem(pTarget);
        pItem->Next = m_pHead;
        if (m_pHead != NULL)
        {
            m_pHead->Prev = pItem;
        }
        m_pHead = pItem;
        m_count++;
        return pItem;
    }

    TArrayPtr< TRefCountedPtr<ListItem> > CopyToArray()
    {
        if(m_count == 0)
        {
            return NULL;
        }

        TArrayPtr< TRefCountedPtr<ListItem> > itemArray = array_allocate< TRefCountedPtr<ListItem> >(m_count);
        ListItem* pNext = m_pHead;
        int num = 0;
        while (pNext != NULL)
        {
            itemArray[num++] = pNext;
            pNext = pNext->Next;
        }
        return itemArray;
    }

    void Remove(ListItem* pT)
    {
        if (pT->InUse)
        {
            if (pT->Prev == NULL)
            {
                m_pHead = pT->Next;
            }
            else
            {
                pT->Prev->Next = pT->Next;
            }
            if (pT->Next != NULL)
            {
                pT->Next->Prev = pT->Prev;
            }
            reuseListItem(pT);
            m_count--;
        }
    }

#pragma region Internal Methods

private:

#pragma region Private Methods

    TRefCountedPtr<ListItem> getNewListItem(Object* pTarget)
    {
        TRefCountedPtr<ListItem> pItem;
        if (m_pPocket != NULL)
        {
            pItem = m_pPocket;
            m_pPocket = pItem->Next;
            m_pocketSize--;
            pItem->Next = pItem->Prev = NULL;
        }
        else
        {
            pItem = object_allocate<ListItem>();
        }
        pItem->Target = pTarget;
        pItem->InUse = true;
        return pItem;
    }

    void reuseListItem(ListItem* pT)
    {
        pT->Target = NULL;
        pT->Next = pT->Prev = NULL;
        pT->InUse = false;
        if (m_pocketSize < PocketCapacity)
        {
            pT->Next = m_pPocket;
            m_pPocket = pT;
            m_pocketSize++;
        }
    }

#pragma endregion Private Methods

#pragma region Private Fields

    int m_count;
    TRefCountedPtr<ListItem> m_pHead;
    TRefCountedPtr<ListItem> m_pPocket;
    int m_pocketSize;
    static const int PocketCapacity = 0x99;

#pragma endregion Private Fields

};


}; // namespace AVUI
